package com.dean.pokeking.ui

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dean.pokeking.*
import com.dean.pokeking.beans.LineupList
import com.dean.pokeking.beans.MonsterButton
import com.dean.pokeking.beans.MonsterList
import com.dean.pokeking.beans.PlayerList
import com.dean.pokeking.repository.NpcDataRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

/**
 * @ClassName MainViewModel
 * @Description MainViewModel
 * @Author Dean
 * @Date 2023/3/22
 * @Version 1.0
 */

data class MainState(
    var npcLineup: List<LineupList> = emptyList(),
    var npcMonsterList: List<MonsterList> = emptyList(),
    var npcMonsterButtonList: List<MonsterButton> = emptyList(),
    var currentPage: PageType = PageType.PlaceChoosePage,
    var currentPlace: String = PLACE_GUANDU,
    var currentNpc: String = GUANDU_NPC[0],
    var currentTeam: String = "",
    var starterMonster: String = "",
    var filterMonsterList: List<MonsterList> = emptyList(),
    var showFilterPage: Boolean = false,
    var teamList: List<String> = emptyList()
)

class MainViewModel : ViewModel() {

    private val _mainState: MutableStateFlow<MainState> = MutableStateFlow(MainState())
    val mainState: StateFlow<MainState> = _mainState

    private val repository: NpcDataRepository = NpcDataRepository.getInstance()

    private var currentNpcAllLineupList: List<LineupList> = emptyList()

    //用于保存当前选中的monster共有的队伍
    private val filtersLineupSet: Set<Int>
        get() {
            val filterList = _mainState.value.filterMonsterList
            return if (filterList.isNotEmpty()) {
                filterList.map { it.lineupSet.toSet() }
                    .reduce { acc, l -> acc.intersect(l) }
            } else {
                emptySet()
            }
        }

    override fun onCleared() {
        super.onCleared()
        val sharedPreference = MainApplication.getAppContext().getSharedPreferences(MY_SP, 0)
        if (sharedPreference.getString(CURRENT_TEAM, "") != _mainState.value.currentTeam) {
            sharedPreference.edit().putString(CURRENT_TEAM, _mainState.value.currentTeam).apply()
        }
    }

    fun initData() {
        viewModelScope.launch {
            if (_mainState.value.currentTeam == "") {
                val sp = MainApplication.getAppContext().getSharedPreferences(MY_SP, 0)
                val teamName = sp.getString(CURRENT_TEAM, "小蛋队")!!
                _mainState.value.currentTeam = teamName
            }
            repository.initData(_mainState.value.currentTeam)
        }
    }

    fun showFilterPage(show: Boolean) = viewModelScope.launch {
        _mainState.update { it.copy(showFilterPage = show) }
    }

    fun savePlayer(player: PlayerList) {
        viewModelScope.launch {
            repository.savePlayerToExcel(_mainState.value.currentTeam, player)
        }
    }

    fun gotoSettingsPage() {
        viewModelScope.launch {
            _mainState.update {
                it.copy(
                    teamList = repository.getAllTeamName(),
                    currentPage = PageType.SettingsPage
                )
            }
        }
    }

    fun setCurrentTeam(teamName: String) {
        viewModelScope.launch {
            _mainState.update {
                it.copy(currentTeam = teamName)
            }
        }
    }

    fun addFilterMonster(monsterName: String) {
        viewModelScope.launch(Dispatchers.IO) {
            _mainState.update {
                val monster =
                    _mainState.value.npcMonsterList.find { it1 -> it1.name == monsterName }
                val filterList = it.filterMonsterList.toMutableList()
                monster?.let { theMonster ->
                    if (!filterList.contains(theMonster)) {
                        filterList.add(theMonster)
                    }
                }
                val newLineupList = currentNpcAllLineupList.filter {
                    filterList.all { theMonster ->
                        it.playerList?.any { playerList -> playerList.name == theMonster.name }
                            ?: false
                    }
                }
                it.copy(filterMonsterList = filterList, npcLineup = newLineupList)
            }
        }
    }

    /**
     * 过滤器中的monster是否需要显示
     */
    fun shouldShow(monsterName: String): Boolean {
        //当filter为空时, 就需要显示所有monster
        if (filtersLineupSet.isEmpty()) return true
        var result = false
        val monsterTeamList =
            _mainState.value.npcMonsterList.find { it.name == monsterName }?.lineupSet
        monsterTeamList?.let {
            result = filtersLineupSet.intersect(it.toSet()).isNotEmpty()
        }
        return result
    }

    fun removeFilterMonster(monsterName: String) {
        viewModelScope.launch {
            _mainState.update {
                val filterList = it.filterMonsterList.toMutableList()
                filterList.removeIf { monster -> monster.name == monsterName }
                var newLineupList = currentNpcAllLineupList
                if (filterList.isNotEmpty()) {
                    newLineupList = currentNpcAllLineupList.filter {
                        filterList.all { theMonster ->
                            it.playerList?.any { playerList -> playerList.name == theMonster.name }
                                ?: false
                        }
                    }
                }
                it.copy(filterMonsterList = filterList, npcLineup = newLineupList)
            }
        }
    }

    fun setCurrentPage(page: PageType) = _mainState.update { it.copy(currentPage = page) }

    fun setCurrentNpc(npcName: String) {
        viewModelScope.launch(Dispatchers.IO) {
            currentNpcAllLineupList = repository.getNpcLineupByNpcName(npcName)
            _mainState.update {
                it.copy(
                    currentNpc = npcName,
                    npcMonsterButtonList = emptyList(),
                    npcLineup = currentNpcAllLineupList,
                    npcMonsterList = repository.getNpcMonsterListByNpcName(npcName)
                )
            }
            setCurrentPage(PageType.MonstersChoosePage)
        }
    }

    fun gotoNextNpc() {
        viewModelScope.launch {
            val currentNpc = _mainState.value.currentNpc
            val list = getNpcsListByPlace(_mainState.value.currentPlace)
            val index = list.indexOf(currentNpc)
            val nextNpc = if (index == -1 || index == list.lastIndex) {
                null
            } else {
                list[index + 1]
            }
            nextNpc?.let {
                setCurrentNpc(it)
            }
        }
    }

    fun setCurrentPlace(placeName: String) {
        viewModelScope.launch(Dispatchers.IO) {
            _mainState.update { it.copy(currentPlace = placeName) }
            setCurrentPage(PageType.EnemyChoosePage)
        }
    }

    fun getNpcsListByPlace(placeName: String): List<String> {
        return when (placeName) {
            PLACE_GUANDU -> GUANDU_NPC
            PLACE_FENGYUAN -> FENGYUAN_NPC
            PLACE_HEZHONG -> HEZHONG_NPC
            PLACE_SHENAO -> SHENAO_NPC
            else -> emptyList()
        }
    }

    fun getNpcMonsterListByNpcName(name: String): Flow<List<MonsterList>> {
        viewModelScope.launch(Dispatchers.IO) {
            _mainState.update { it.copy(npcMonsterList = repository.getNpcMonsterListByNpcName(name)) }
        }
        return _mainState.map { it.npcMonsterList }
    }

    fun getNpcMonsterButtonListByNpcName(name: String): Flow<List<MonsterButton>> {
        viewModelScope.launch(Dispatchers.IO) {
            val buttonList = repository.getNpcMonsterListByNpcName(name)
                .map {
                    MonsterButton(it.id, it.name ?: "", it.lineupSet?.size ?: 0)
                }
            _mainState.update { it.copy(npcMonsterButtonList = buttonList) }
        }
        return _mainState.map { it.npcMonsterButtonList }
    }

    fun setCurrentMonster(monsterName: String) {
        viewModelScope.launch {
            _mainState.update {
                it.copy(filterMonsterList = emptyList())
            }
            addFilterMonster(monsterName)
            setCurrentPage(PageType.NpcTeamInfoPage)
        }
    }
}
